package org.transfer.service;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileWriter;
import java.io.InputStreamReader;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.transfer.datasource.CreateDatasource;
import org.transfer.datasource.DataSourceContextHolder;
import org.transfer.model.ImportLog;
import org.transfer.utils.ConfigUtil;
import org.transfer.utils.LogUtils;
import org.transfer.utils.MysqlInfo;
import org.transfer.utils.SqlServerUtil;

@Component
public class OriginalMySqlService {

	// 日志文件存放目录
	private String logPath = "";
	// 恢复文件存放目录
	private static String recoveryPath = "";

	List<File> logFiles = new ArrayList<File>();

	private String userName = "";
	private String passWord = "";
	private String ip = "";
	private String port = "";
	private String db = "";

	private String DBName = "";

	@Autowired
	private ImportLogService importLogService;

	private String recoveryLogPath = "";

	/**
	 * 执行恢复
	 */
	public void recoveryData() throws Exception {
		System.out.println("===================MySql数据恢复开始===================");
		logPath = ConfigUtil.getConfigure().getProperty("sqlLogsFile");
		recoveryPath = ConfigUtil.getConfigure().getProperty("recoveryPath");
		scanningFile(logFiles, logPath);
		userName = ConfigUtil.getConfigure().getProperty("mySqlUsername");
		passWord = ConfigUtil.getConfigure().getProperty("mySqlPassword");
		ip = ConfigUtil.getConfigure().getProperty("mySqlHostname");
		port = ConfigUtil.getConfigure().getProperty("mySqlDBport");
		db = ConfigUtil.getConfigure().getProperty("mySqlqlDBname");
		File logFile = new File(logPath);
		if (!logFile.exists()) {
			logFile.mkdirs();
		}
		recoveryLogPath = logPath + "recovery.log";
		List<File> list = new ArrayList<File>();
		scanningFile(list, recoveryPath);
		for (File file : list) {
			String fileName = file.getName().toUpperCase();
			if (fileName.indexOf("SQL") != -1 && fileName.indexOf(".") != -1
					&& "SQL".equals(fileName.substring(fileName.lastIndexOf(".") + 1, fileName.length()))) {

				ImportLog entity = importLogService
						.get(new ImportLog(file.getName().substring(0, file.getName().indexOf("."))));
				if (entity != null) {
					entity.setBakType("1");
				}
				try {
					recoveryMySql(file.getPath(), file.getName());
					System.out.println("===================" + DBName + "数据恢复===================");
					LogUtils.logs(recoveryLogPath, "【" + file.getName() + "】-【" + DBName + "】恢复成功");
					if (entity != null) {
						entity.setRecoveryState("1");
						entity.setRecoveryMsg("恢复成功");
						importLogService.save(entity);
					}
				} catch (Exception e) {
					e.printStackTrace();
					LogUtils.logs(recoveryLogPath, "【" + file.getName() + "】恢复失败");
					if (entity != null) {
						entity.setRecoveryState("0");
						entity.setRecoveryMsg("恢复失败");
						importLogService.save(entity);
					}
				}
			} else {
				LogUtils.logs(recoveryLogPath, "【" + file.getName() + "】无需恢复");
			}
		}
		System.out.println("===================MySql数据恢复结束===================");
	}

	/**
	 * 执行恢复
	 * 
	 * @param filePath
	 * @throws Exception
	 */
	public void recoveryMySql(String filePath, String fileName) throws Exception {
		String filepathtemp = "";
		String dbName = "";
		String newDbName = "";
		String tempstr1 = "";
		Map<String, Object> map = new HashMap<String, Object>();
		List<String> fileList = new ArrayList<>();
		BufferedWriter bufferedWriter = null;
		FileWriter fileWriter = null;
		Process process = null;
		int num = 0;
		// log文件的地址
		StringBuffer logFilePath = new StringBuffer();
		StringBuffer logFilePath1 = new StringBuffer();
		StringBuffer logFilePath2 = new StringBuffer();
		StringBuffer logFilePathtemp = new StringBuffer();
		// sql文件的地址
		StringBuffer sqlFilePath = new StringBuffer();
		StringBuffer sqlFilePath1 = new StringBuffer();
		StringBuffer sqlFilePath2 = new StringBuffer();
		StringBuffer sqlFilePathtemp = new StringBuffer();
		// sql文件的地址
		StringBuffer batFilePath = new StringBuffer();
		StringBuffer batFilePath1 = new StringBuffer();
		StringBuffer batFilePath2 = new StringBuffer();
		StringBuffer batFilePathtemp = new StringBuffer();
		// 拼接字符串
		StringBuffer temp = new StringBuffer();
		StringBuffer temp1 = new StringBuffer();
		// 数据库信息
		map = MysqlInfo.getInfo(filePath);
		boolean b = (boolean) map.get("result");
		dbName = (String) map.get("dbName");
		fileList = (List<String>) map.get("list");
		if (b == true) {
			newDbName = "db_" + new SimpleDateFormat("yyyyMMddHHmmss").format(new Date());
			ImportLog entity = importLogService.get(new ImportLog(fileName.substring(0, fileName.indexOf("."))));
			if (entity == null) {
				throw new RuntimeException("恢复失败");
			}
			if ("1".equals(entity.getRecoveryState())) {
				return;
			}
			if (StringUtils.isBlank(entity.getDbName()) || StringUtils.isBlank(entity.getNewDbName())) {
				entity.setDbName(dbName);
				entity.setNewDbName(newDbName);
				importLogService.save(entity);
			} else {
				newDbName = entity.getNewDbName();
			}
			DBName = newDbName;
			/*
			 * for (File file : logFiles) { if (file.isFile()) { String name =
			 * file.getName(); if (file.getName().indexOf(dbName) != -1) {
			 * return; } } }
			 */
			sqlFilePath.append(logPath + newDbName + "-createdatabase.sql");
		} else {
			throw new RuntimeException("无法解析该SQL文件");
		}
		try {
			// 创建sql文件用于存放执行的sql语句
			File file = new File(sqlFilePath.toString());
			fileWriter = new FileWriter(file);
			bufferedWriter = new BufferedWriter(fileWriter);
			bufferedWriter.write("CREATE DATABASE /*!32312 IF NOT EXISTS*/ `" + newDbName
					+ "` /*!40100 DEFAULT CHARACTER SET utf8 */;");
			try {
				bufferedWriter.flush();
				fileWriter.flush();
				if (bufferedWriter != null) {
					bufferedWriter.close();
				}
				if (fileWriter != null) {
					fileWriter.close();
				}
			} catch (Exception e) {
				String name = "关闭读写文件所需的io流时失败!";
				throw new RuntimeException(name);
			}
		} catch (Exception e) {
			String name = "生成创建数据库的sql语句文件失败!";
			throw new RuntimeException(name);
		}
		batFilePath.append(logPath + newDbName + "-createdatabase.bat");
		File file = new File(batFilePath.toString());
		fileWriter = new FileWriter(file);
		bufferedWriter = new BufferedWriter(fileWriter);
		bufferedWriter.write(
				"mysql -S " + ip + "," + port + " -u " + userName + " -p" + passWord + " -D" + db + "<" + sqlFilePath);
		try {
			bufferedWriter.flush();
			fileWriter.flush();
			if (bufferedWriter != null) {
				bufferedWriter.close();
			}
			if (fileWriter != null) {
				fileWriter.close();
			}
		} catch (Exception e) {
			String name = "生成创建数据库的bat文件失败!";
			throw new RuntimeException(name);
		}
		process = MysqlInfo.cmd(batFilePath.toString());
		try {
			// 输出语句
			logFilePath.append(logPath + newDbName + "-createdatabase.log");
			File file1 = new File(logFilePath.toString());
			fileWriter = new FileWriter(file1);
			bufferedWriter = new BufferedWriter(fileWriter);
			// 从工具类中获取日志信息 process.getErrorStream()
			InputStreamReader isr1 = new InputStreamReader(process.getErrorStream(), "GB2312");
			BufferedReader br1 = new BufferedReader(isr1);
			String line = null;
			bufferedWriter.write((new Date()).toString() + " 开始创建数据库" + System.lineSeparator());
			while ((line = br1.readLine()) != null) {
				temp.append(line + System.lineSeparator());
			}
			InputStreamReader isr = new InputStreamReader(process.getInputStream(), "GB2312");
			BufferedReader br = new BufferedReader(isr);
			while ((line = br.readLine()) != null) {
				temp1.append(line + System.lineSeparator());
			}
			bufferedWriter.write("执行命令:" + System.lineSeparator());
			bufferedWriter.write(temp1.toString() + System.lineSeparator());
			bufferedWriter.write("日志信息:" + System.lineSeparator());
			bufferedWriter.write(temp.toString() + System.lineSeparator());
			bufferedWriter.write((new Date()).toString() + "创建数据库结束");
			br.close();
			isr.close();
			br1.close();
			isr1.close();
			if (temp.toString().contains("ERROR") || temp1.toString().contains("ERROR")) {
				String name = "创建数据库失败!";
				throw new RuntimeException(name);
			}
			if ("".equals(temp.toString())) {
				// 没有错误日志则恢复成功
				/*
				 * String dbLogName = getDbLogName(fileName, dbName); FileWriter
				 * fw = new FileWriter(logPath + dbLogName + ".log");
				 * fw.write("恢复成功"); fw.close();
				 */
			}
		} catch (Exception e) {
			String name = "生成创建数据库日志失败!";
			throw new RuntimeException(name);
		} finally {
			try {
				bufferedWriter.flush();
				fileWriter.flush();
				if (bufferedWriter != null) {
					bufferedWriter.close();
				}
				if (fileWriter != null) {
					fileWriter.close();
				}
			} catch (Exception e) {
				String name = "关闭读写文件的io流失败!";
				throw new RuntimeException(name);
			}
			try {
				if (process != null) {
					process.destroy();
				}
				process.getErrorStream().close();
				process.getInputStream().close();
				process.getOutputStream().close();
			} catch (Exception ee) {
				String name = "关闭cmd工具流失败!";
				throw new RuntimeException(name);
			}
			// fileUtil.uploadAndDeLeteLog(logFilePath.toString(), bucket);
			for (int i = 0; i < fileList.size(); i++) {
				logFilePathtemp = new StringBuffer();
				batFilePathtemp = new StringBuffer();
				sqlFilePathtemp = new StringBuffer();
				filepathtemp = fileList.get(i);
				if (i == 0) {
					sqlFilePath1.append(logPath + newDbName + "-createtable.sql");
					sqlFilePathtemp = sqlFilePath1;
				} else if (i == 1) {
					sqlFilePath2.append(logPath + newDbName + "-createtable-data.sql");
					sqlFilePathtemp = sqlFilePath2;
				}

				MysqlInfo.getsql(filepathtemp, sqlFilePathtemp.toString());

				if (i == 0) {
					batFilePath1.append(logPath + newDbName + "-createtable.bat");
					batFilePathtemp = batFilePath1;
				} else if (i == 1) {
					batFilePath2.append(logPath + newDbName + "-createtable-data.bat");
					batFilePathtemp = batFilePath2;
				}

				File file2 = new File(batFilePathtemp.toString());
				fileWriter = new FileWriter(file2);
				bufferedWriter = new BufferedWriter(fileWriter);
				bufferedWriter.write("mysql -S " + ip + "," + port + " -u " + userName + " -p" + passWord + " -D"
						+ newDbName + "<" + sqlFilePathtemp);
				try {
					bufferedWriter.flush();
					fileWriter.flush();
					if (bufferedWriter != null) {
						bufferedWriter.close();
					}
					if (fileWriter != null) {
						fileWriter.close();
					}
				} catch (Exception e) {
					String name = "生成恢复数据库的bat语句文件失败!";
					throw new RuntimeException(name);
				}
				process = MysqlInfo.cmd(batFilePathtemp.toString());
				try {
					// 输出语句
					if (i == 0) {
						logFilePath1.append(logPath + newDbName + "-createtable.log");
						logFilePathtemp = logFilePath1;
					} else if (i == 1) {
						logFilePath2.append(logPath + newDbName + "-createtable-data.log");
						logFilePathtemp = logFilePath2;
					}
					File file3 = new File(logFilePathtemp.toString());
					fileWriter = new FileWriter(file3);
					bufferedWriter = new BufferedWriter(fileWriter);
					// 从工具类中获取日志信息 process.getErrorStream()
					InputStreamReader isr1 = new InputStreamReader(process.getErrorStream(), "GB2312");
					BufferedReader br1 = new BufferedReader(isr1);
					String line = null;
					temp.delete(0, temp.length() + 1);
					temp1.delete(0, temp1.length() + 1);
					bufferedWriter.write((new Date()).toString() + " 开始恢复数据库" + System.lineSeparator());
					while ((line = br1.readLine()) != null) {
						temp.append(line + System.lineSeparator());
					}
					InputStreamReader isr = new InputStreamReader(process.getInputStream(), "GB2312");
					BufferedReader br = new BufferedReader(isr);
					while ((line = br.readLine()) != null) {
						temp1.append(line + System.lineSeparator());
					}
					bufferedWriter.write("执行命令:" + System.lineSeparator());
					bufferedWriter.write(temp1.toString() + System.lineSeparator());
					bufferedWriter.write("日志信息:" + System.lineSeparator());
					bufferedWriter.write(temp.toString() + System.lineSeparator());
					bufferedWriter.write((new Date()).toString() + "恢复数据库结束");
					br.close();
					isr.close();
					br1.close();
					isr1.close();
					if (temp.toString().contains("ERROR") || temp1.toString().contains("ERROR")) {
						String name = "恢复数据库失败!";
						throw new RuntimeException(name);
					}

				} catch (Exception e) {
					String name = "生成恢复数据库日志失败!";
					throw new RuntimeException(name);
				} finally {
					try {
						bufferedWriter.flush();
						fileWriter.flush();
						if (bufferedWriter != null) {
							bufferedWriter.close();
						}
						if (fileWriter != null) {
							fileWriter.close();
						}
						if (process != null) {
							process.destroy();
						}
					} catch (Exception e) {
						String name = "关闭读写文件的io流失败!";
						throw new RuntimeException(name);
					}
					try {
						process.getErrorStream().close();
						process.getInputStream().close();
						process.getOutputStream().close();
					} catch (Exception ee) {
						String name = "关闭cmd工具流失败!";
						throw new RuntimeException(name);
					}
				}
				// fileUtil.uploadAndDeLeteLog(logFilePathtemp.toString(), "");
			}
			int dataNum = 0;
			// 恢复的表数量
			Integer tableNum = null;
			// 设置连接数据库的url 用户 密码 库名
			linkMysqlDataBase();
			// 恢复的数据条数
			/*
			 * try {
			 * 
			 * List<String> list =
			 * originalDatabaseMapper.selectMysqlDataNum1(newDbName); if
			 * (list.size() > 2) { String tempstr = list.get(list.size() - 2);
			 * tempstr = tempstr.replace("union all", ""); list.set(list.size()
			 * - 2, tempstr); for (int i = 0; i < list.size(); i++) { String
			 * temp2 = list.get(i); tempstr1 += (temp2 +
			 * System.lineSeparator()); } } num =
			 * originalDatabaseMapper.selectMysqlDataNum2(tempstr1); // 恢复的表数量
			 * tableNum = originalDatabaseMapper.selectMysqlTableNnm(newDbName);
			 * 
			 * } catch (Exception e) { String name = "查询数据库信息失败!"; throw new
			 * RuntimeException(name); }
			 */
			deleteFile(sqlFilePath.toString());
			deleteFile(sqlFilePath1.toString());
			deleteFile(batFilePath.toString());
			deleteFile(batFilePath1.toString());
			if (fileList.size() == 2) {
				deleteFile(sqlFilePath2.toString());
				deleteFile(batFilePath2.toString());
			}
		}
	}

	/**
	 * 删除恢复过程中产生的文件
	 *
	 * @param Path
	 */
	public boolean deleteFile(String Path) throws Exception {
		boolean isTrue = false;
		try {
			File file = new File(Path);
			isTrue = file.delete();
		} catch (Exception e) {
			String name = "删除恢复过程中生成的临时文件失败!";
			throw new RuntimeException(name);
		}
		return isTrue;
	}

	/**
	 * mysql数据链接
	 *
	 * @param dataSource
	 * @param dbName
	 * @throws Exception
	 */

	public void linkMysqlDataBase() throws Exception {
		try {
			// 数据库连接地址
			String adminUrl = "jdbc:mysql://" + ip + ":" + port + "/" + db;

			// 创建新的数据源
			// 驱动名称
			String driverClassName = "com.mysql.jdbc.Driver";
			// 自定义数据源名称
			String sourceName = "mysql";
			CreateDatasource createDatasource = new CreateDatasource();
			createDatasource.createDatasourec(adminUrl, userName, passWord, driverClassName, sourceName);
			// 切换数据源
			DataSourceContextHolder.setDBType(sourceName);

		} catch (Exception e) {
			String name = "创建数据连接失败!";
			throw new RuntimeException(name);
		}
	}

	/**
	 * 数据授权
	 * 
	 * @param filePath
	 */
	public void AccessPermission(String filePath) {
		Process process = null;
		try {
			// 把当前文件的完全控制权限授权所有人
			// 获取管理员权限
			process = SqlServerUtil.cmd("net localgroup administrators " + System.getProperty("user.name") + " /add");
			// 执行命令
			process = SqlServerUtil
					.cmd("cacls " + filePath.substring(0, filePath.length() - 1) + " /T /E /C /G everyone:F");
			// 获取管理员权限
			process = SqlServerUtil
					.cmd("net localgroup administrators " + System.getProperty("user.name") + " /delete");
		} catch (Exception e) {
			throw new RuntimeException("获取恢复文件完全访问权限失败!");
		} finally {
			if (process != null) {
				process.destroy();
			}
			try {
				process.getErrorStream().close();
				process.getInputStream().close();
				process.getOutputStream().close();
			} catch (Exception ee) {
				throw new RuntimeException("关闭cmd工具流失败!");
			}
		}
	}

	/**
	 * 检查路径下所有文件并返回list
	 * 
	 * @param list
	 * @param filePath
	 * @return
	 */
	public List<File> scanningFile(List<File> list, String filePath) {
		File document = new File(filePath);
		if (!document.exists()) {
			document.mkdirs();
		}
		if (!document.isFile()) {
			File[] files = document.listFiles();
			for (File file : files) {
				scanningFile(list, file.getPath());
			}
		} else {
			list.add(document);
		}
		return list;
	}

}
